package org.orbis.spikezolt;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import java.io.IOException;
import org.anddev.andengine.engine.camera.hud.HUD;
import org.anddev.andengine.audio.music.Music;
import org.anddev.andengine.audio.music.MusicFactory;
import org.anddev.andengine.audio.sound.Sound;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.BoundCamera;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.Entity;
import org.anddev.andengine.entity.IEntity;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXObject;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXObjectGroup;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperties;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTileProperty;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;

import org.anddev.andengine.entity.modifier.MoveXModifier;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.scene.background.SpriteBackground;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.text.ChangeableText;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.extension.input.touch.controller.MultiTouch;
import org.anddev.andengine.extension.input.touch.controller.MultiTouchController;
import org.anddev.andengine.extension.input.touch.exception.MultiTouchException;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.util.Box2dDebugRenderer;
import org.anddev.andengine.extension.physics.box2d.util.Vector2Pool;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.ScrollDetector;
import org.anddev.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
import org.anddev.andengine.input.touch.detector.SurfaceScrollDetector;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Callback;
import org.anddev.andengine.util.Debug;
import org.anddev.andengine.util.FileUtils;

import com.badlogic.gdx.math.Vector2;
import org.anddev.andengine.entity.shape.Shape;
import org.helllabs.android.xmp.ModPlayer;

import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;

import android.graphics.Color;
import android.graphics.Typeface;
import android.hardware.SensorManager;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;

public class SpikeZoltActivity extends BaseGameActivity implements
		IOnSceneTouchListener, IAccelerometerListener {
	private static final int CAMERA_WIDTH = 320;
	private static final int CAMERA_HEIGHT = 240;

	public final int PLAYER_DEPTH = 3;
	public final int OTHER_DEPTH = 1;
	public final int ENDTUBE_DEPTH_TOP = 4;
	public final int ENDTUBE_DEPTH_LOW = 2;
	
	public MapLoader mapLoader;

	public BoundCamera mCamera;
	private BitmapTextureAtlas mBitmapTextureAtlas;
	
	public TMXLoader tmxLoader;

	public PhysicsWorld mPhysicsWorld;

	public final float WALL_FRICTION = 0.05f;

	public ArrayList<Updater> steps = new ArrayList<Updater>();
	public ArrayList<Block> blocks = new ArrayList<Block>();

	HUD mainHud;
	GameHUD hud;

	public Engine mEngine;

	public Scene scene;

	public TextureManager texManager;

	Player pl;

	private Sprite bgSprite;
	private TextureRegion bgTexture;

	private Music mainTheme;
	public SoundPlayer sndPlayer;

	private static final String SAMPLE_MOD_DIRECTORY = "mfx/";
	private static final String SAMPLE_MOD_FILENAME = "7thheaven.mod";
	private final ModPlayer mModPlayer = ModPlayer.getInstance();

	public Font bFont, wFont;
	private BitmapTextureAtlas mFontTexture;
	private ChangeableText debugText;

	private float mTouchX = 0, mTouchY = 0, mTouchOffsetX = 0,
			mTouchOffsetY = 0;

	public void onLoadComplete() {
		// TODO Auto-generated method stub
	}

	@Override
	public final void onPause() {
		super.onPause();
		this.mModPlayer.stop();
		if (mainTheme != null) {
			// mainTheme.pause();
		}
	}

	@Override
	public final void onResume() {
		super.onResume();

		if (mainTheme != null) {
			// mainTheme.play();
		}
	}

	public Engine onLoadEngine() {
		this.mCamera = new BoundCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);

		mEngine = new Engine(new EngineOptions(true,
				ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(
						CAMERA_WIDTH, CAMERA_HEIGHT), mCamera).setNeedsSound(
				true).setNeedsMusic(true));

		mainHud = new HUD();
		mCamera.setHUD(mainHud);

		// enabling MultiTouch if available
		try {
			if (MultiTouch.isSupported(this)) {
				mEngine.setTouchController(new MultiTouchController());
			} else {
				Log.d("Orbis", "Sorry your device does NOT support MultiTouch!");
			}
		} catch (final MultiTouchException e) {
			Log.d("Orbis", "Sorry your device does NOT support MultiTouch!");
		}

		sndPlayer = new SoundPlayer(this);

		return mEngine;// new Engine(engineOptions);
	}

	public void onLoadResources() {
		Log.d("Orbis", "RESOURCES LOAD");
		// this.startPlayingMod();
		// prepare a container for the image
		this.mBitmapTextureAtlas = new BitmapTextureAtlas(512, 512,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);

		// loading the image inside the container

		this.bgTexture = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mBitmapTextureAtlas, this, "gfx/bg0.png", 0, 0);

		texManager = new TextureManager(this);

		mFontTexture = new BitmapTextureAtlas(256, 256,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		bFont = new Font(mFontTexture, Typeface.create(Typeface.DEFAULT,
				Typeface.BOLD), 40, true, Color.BLACK);
		wFont = new Font(mFontTexture, Typeface.create(Typeface.DEFAULT,
				Typeface.BOLD), 40, true, Color.BLACK);
		mEngine.getTextureManager().loadTexture(mFontTexture);
		mEngine.getFontManager().loadFont(bFont);
		mEngine.getFontManager().loadFont(wFont);

		this.mEngine.getTextureManager().loadTexture(mBitmapTextureAtlas);

		this.bFont = new Font(this.mFontTexture, Typeface.create(
				Typeface.DEFAULT, Typeface.BOLD), 32, true, Color.BLACK);
		this.wFont = new Font(this.mFontTexture, Typeface.create(
				Typeface.DEFAULT, Typeface.BOLD), 32, true, Color.BLACK);

		if (FileUtils.isFileExistingOnExternalStorage(this,
				SAMPLE_MOD_DIRECTORY + SAMPLE_MOD_FILENAME)) {
			this.startPlayingMod();
		} else {
			this.doAsync(
					R.string.dialog_modplayerexample_loading_to_external_title,
					R.string.dialog_modplayerexample_loading_to_external_message,
					new Callable<Void>() {

						@Override
						public Void call() throws Exception {
							FileUtils.ensureDirectoriesExistOnExternalStorage(
									SpikeZoltActivity.this,
									SAMPLE_MOD_DIRECTORY);
							FileUtils.copyToExternalStorage(
									SpikeZoltActivity.this,
									SAMPLE_MOD_DIRECTORY + SAMPLE_MOD_FILENAME,
									SAMPLE_MOD_DIRECTORY + SAMPLE_MOD_FILENAME);
							return null;
						}
					}, new Callback<Void>() {

						@Override
						public void onCallback(final Void pCallbackValue) {
							startPlayingMod();
						}
					});
		}

	}

	public void startPlayingMod() {
		// this.mModPlayer.play("mfx/7thheaven.mod");
		/*
		 * this.mModPlayer.play(FileUtils.getAbsolutePathOnExternalStorage(this,
		 * SAMPLE_MOD_DIRECTORY + SAMPLE_MOD_FILENAME));
		 */
		this.mModPlayer.play(FileUtils.getAbsolutePathOnInternalStorage(this,
				"mfx/7thheaven.mod"));
	}

	public Scene onLoadScene() {
		Log.d("Orbis", "SCENE LOAD");
		this.mEngine.registerUpdateHandler(new FPSLogger());

		scene = new Scene();

		this.mPhysicsWorld = new PhysicsWorld(new Vector2(0,
				SensorManager.GRAVITY_EARTH + 8), false);

		this.mPhysicsWorld.setContactListener(new ContactListener() {

			@Override
			public void beginContact(Contact contact) {
				Object bodyA, bodyB, fixtureA, fixtureB;
				bodyA = contact.getFixtureA().getBody().getUserData();
				bodyB = contact.getFixtureB().getBody().getUserData();
				fixtureA = contact.getFixtureA().getUserData();
				fixtureB = contact.getFixtureB().getUserData();
				if (bodyA != null && fixtureB != null) {
					if (bodyA.equals("wall") && fixtureB.equals("foot")) {
						pl.canJump = true;
					}
				} else if (bodyB != null && fixtureA != null) {
					if (bodyB.equals("wall") && fixtureA.equals("foot")) {
						pl.canJump = true;
					}
				}

			}

			@Override
			public void endContact(Contact contact) {
				// TODO Auto-generated method stub
			}

			@Override
			public void preSolve(Contact contact, Manifold oldManifold) {
				// TODO Auto-generated method stub

			}

			@Override
			public void postSolve(Contact contact, ContactImpulse impulse) {
				// TODO Auto-generated method stub

			}

		});

		// Background Setup
		bgSprite = new Sprite(0, 0, bgTexture);
		SpriteBackground bg = new SpriteBackground(bgSprite);
		scene.setBackground(bg);
		mapLoader = new MapLoader(this);
		mapLoader.load("map0");
/*
		// TMXLoader Initialization
		try {
				TMXLoader tmxLoader = new TMXLoader(this,
					this.mEngine.getTextureManager(),
					TextureOptions.BILINEAR_PREMULTIPLYALPHA,
					new ITMXTilePropertiesListener() {
						@Override
						public void onTMXTileWithPropertiesCreated(
								final TMXTiledMap pTMXTiledMap,
								final TMXLayer pTMXLayer,
								final TMXTile pTMXTile,
								final TMXProperties<TMXTileProperty> pTMXTileProperties) {

						}
					});

			this.currentMap = tmxLoader.loadFromAsset(this, "tmx/map0.tmx");

			// OBJECTS
			ArrayList<TMXObjectGroup> objs = currentMap.getTMXObjectGroups();
			for (int i = 0; i < objs.size(); i++) {
				String objGroupName = objs.get(i).getName();

				if (objGroupName.equals("blocks")) {
					int numOfObjects = objs.get(i).getTMXObjects().size();
					for (int k = 0; k < numOfObjects; k++) {
						TMXObject tmxObject = objs.get(i).getTMXObjects()
								.get(k);
						int x = tmxObject.getX();
						int y = tmxObject.getY();
						int width = tmxObject.getWidth();
						int height = tmxObject.getHeight();
						String tmxName = tmxObject.getName();
						int xx = x, yy = y;
						if ((width % 16 == 0) && (height % 16 == 0)) {
							xx = width / 16;
							yy = height / 16;

							for (int w = 0; w < xx; w++) {
								for (int h = 0; h < yy; h++) {
									Block b = new Block(this, x + (w * 16), y
											+ (h * 16), 16, 16, tmxName);
									blocks.add(b);
								}
							}
						}
					}
				}

				else if (objGroupName.equals("walls")) {
					int numOfObjects = objs.get(i).getTMXObjects().size();
					for (int k = 0; k < numOfObjects; k++) {
						TMXObject wall = objs.get(i).getTMXObjects().get(k);
						final Shape boxShape = new Rectangle(wall.getX(),
								wall.getY(), wall.getWidth(), wall.getHeight());
						final FixtureDef wallFixtureDef = PhysicsFactory
								.createFixtureDef(0, 0.5f, 0.5f);
						// wallFixtureDef.isSensor = true;
						wallFixtureDef.restitution = 0.0f;
						wallFixtureDef.friction = WALL_FRICTION;
						Body body = PhysicsFactory.createBoxBody(
								this.mPhysicsWorld, boxShape,
								BodyType.StaticBody, wallFixtureDef);
						body.setUserData("wall");
					}
				}

				else if (objGroupName.equals("other")) {
					int numOfObjects = objs.get(i).getTMXObjects().size();
					for (int k = 0; k < numOfObjects; k++) {
						TMXObject tmxObject = objs.get(i).getTMXObjects()
								.get(k);
						int x = tmxObject.getX();
						int y = tmxObject.getY();
						String tmxName = tmxObject.getName();
						String tmxType = tmxObject.getType();
						TMXProperties objProps = tmxObject
								.getTMXObjectProperties();
						if (tmxType != null) {
							if (tmxType.equals("switch")) {
								Switch s = new Switch(this, x, y, tmxName);
								steps.add(s);
							}
						}
						if (tmxName.equals("tutorial")) {
							Tutorial tut = new Tutorial(this, x, y, objProps
									.get(0).toString());
							steps.add(tut);
						} else if (tmxName.equals("startPoint")) {
							if (mPhysicsWorld != null) {
								pl = new Player(this, scene, mEngine,
										this.mPhysicsWorld, x, y);
								steps.add(pl);
							}
						} else if (tmxName.equals("endPipe")) {
							if (mPhysicsWorld != null) {
								EndPipe endPipe = new EndPipe(this, x, y);
								steps.add(endPipe);
							}
						}

					}
				}
			}

		} catch (final TMXLoadException tmxle) {
			Debug.e(tmxle);
		}
		*/
		// EOTMX

		// mainTheme.play();

		hud = new GameHUD(this, scene, mainHud, mEngine, pl, CAMERA_WIDTH,
				CAMERA_HEIGHT, mCamera);

		this.mCamera.setChaseEntity(pl.getSprite());

		debugText = new ChangeableText(0, 0, bFont, String.valueOf(10));
		debugText.setText("test....");
		debugText.setPosition(mCamera.getWidth() - debugText.getWidth() - 5, 5);
		scene.attachChild(debugText, 0);

		scene.registerUpdateHandler(this.mPhysicsWorld);

		scene.registerUpdateHandler(new IUpdateHandler() {

			public void reset() {
				// TODO Auto-generated method stub

			}

			public void onUpdate(float pSecondsElapsed) {
				for (int i = 0; i < steps.size(); i++) {
					steps.get(i).step();
				}
			}
		});

		// scene.attachChild(new Box2dDebugRenderer(mPhysicsWorld));

		scene.setOnSceneTouchListener(this);
		scene.setTouchAreaBindingEnabled(false);
		return scene;
	}

	/*
	 * TEMP TEMP!!!!!!!!!111
	 */
	public void onAccelerometerChanged(
			final AccelerometerData pAccelerometerData) {
		// Log.d("Orbis", "X: " + pAccelerometerData.getX());
		// Log.d("Orbis", "Y: " + pAccelerometerData.getY());
		float x = pAccelerometerData.getX();
		float helV = 0;
		if (x < -1)
			helV = -5;
		else if (x > 1)
			helV = 5;
		// else helV = 0;
		// pl.body.setLinearVelocity(helV, pl.body.getLinearVelocity().y);

	}

	@Override
	public void onResumeGame() {
		super.onResumeGame();

		// this.enableAccelerometerSensor(this);
	}

	@Override
	public void onPauseGame() {
		super.onPauseGame();

		// this.disableAccelerometerSensor();
	}

	/*
	 * TEMP TEMP!!!!!!!!!111
	 */

	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pTouchEvent) {
		hud.myTouch(pScene, pTouchEvent);

		float newX = pTouchEvent.getMotionEvent().getX();
		float newY = pTouchEvent.getMotionEvent().getY();

		if (pTouchEvent.getAction() == MotionEvent.ACTION_DOWN) {
			// Log.d("Orbis", "TOUCH!");
		} else if (pTouchEvent.getAction() == MotionEvent.ACTION_MOVE) {
			// Log.d("Orbis", "MOVE!");
		} else if (pTouchEvent.getAction() == MotionEvent.ACTION_UP) {
			// Log.d("Orbis", "RELEASE!");
		}
		return true;
	}

}
